/*
 * @Author: wuqingchun
 * @Date: 2024-06-22 14:04:55
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-06-23 15:36:22
 */
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/epoll.h>

#include "http_poller.h"


CHTTPEventPoller::CHTTPEventPoller(CHTTPLogger& refLogger):
    m_refLogger(refLogger)
{

}

CHTTPEventPoller::~CHTTPEventPoller()
{
    if (m_iEpollFd != -1)
    {
        close(m_iEpollFd);
        m_iEpollFd = -1;
    }
}

int CHTTPEventPoller::Init()
{
    m_iEpollFd = epoll_create(1);
    if (m_iEpollFd == -1)
    {
        HTTP_ERROR(HTTP_SYSCALL_FAIL, "epoll_create error, %s", strerror(errno));
        return HTTP_SYSCALL_FAIL;
    }

    return HTTP_OK;
}

int CHTTPEventPoller::AddEvent(IHTTPEvent& refEvent, EEventType enType)
{
    return __EventCtl(EPOLL_CTL_ADD, refEvent, enType);
}

int CHTTPEventPoller::ModifyEvent(IHTTPEvent& refEvent, EEventType enType)
{
    return __EventCtl(EPOLL_CTL_MOD, refEvent, enType);
}

int CHTTPEventPoller::DeleteEvent(IHTTPEvent& refEvent)
{
    struct epoll_event stEvent;
    return __EventCtl(EPOLL_CTL_DEL, refEvent, EEventType::EVENT_IN);
}

int CHTTPEventPoller::Poll()
{
    if (m_iEpollFd == -1)
    {
        HTTP_ERROR(HTTP_INVALID_POLLER, "invalid poller");
        return HTTP_INVALID_POLLER;
    }

    int iFdNum = epoll_wait(m_iEpollFd, m_astEvents, EVENT_MAX_COUNT, WAIT_TIMEOUT_MS);
    if (iFdNum == -1)
    {
        HTTP_ERROR(HTTP_SYSCALL_FAIL, "epoll_wait error, %s", strerror(errno));
        return HTTP_SYSCALL_FAIL;
    }

    struct epoll_event* pstEvent;

    for (int i = 0; i < iFdNum; i++)
    {
        IHTTPEvent* pobjEvent = (IHTTPEvent*)m_astEvents[i].data.ptr;
        if (pobjEvent == nullptr)
        {
            continue;
        }

        uint32_t uiEvents = pstEvent->events;

        HTTP_DEBUG("Events 0x%x occured", uiEvents);

        if ((uiEvents & EPOLLIN) == EPOLLIN)
        {
            pobjEvent->HandleIn();
        }

        if ((uiEvents & EPOLLOUT) == EPOLLOUT)
        {
            pobjEvent->HandleOut();
        }

        if ((uiEvents & (EPOLLHUP | EPOLLERR)) != 0)
        {
            pobjEvent->HandleError();
            DeleteEvent(*pobjEvent);
        }
    }

    return HTTP_OK;
}

int CHTTPEventPoller::__EventCtl(int iOperType, IHTTPEvent& refEvent, EEventType enType)
{
    struct epoll_event stEvent;

    if (m_iEpollFd == -1)
    {
        return HTTP_INVALID_POLLER;
    }

    int iEventFd = refEvent.GetEventFd();
    if (iEventFd == -1)
    {
        return HTTP_INVALID_EVENT;
    }

    uint32_t uiEvents = 0;
    switch (enType)
    {
    case EEventType::EVENT_IN:
        uiEvents = EPOLLIN;
        break;
    case EEventType::EVENT_OUT:
        uiEvents = EPOLLOUT;
        break;
    default:
        break;
    }

    stEvent.data.ptr = (void*)&refEvent;
    stEvent.events = uiEvents;

    if (epoll_ctl(m_iEpollFd, iOperType, iEventFd, &stEvent) != 0)
    {
        HTTP_ERROR(HTTP_SYSCALL_FAIL, "epoll_ctl error, %s, fd=%d", strerror(errno), iEventFd);
        return HTTP_SYSCALL_FAIL;
    }

    HTTP_INFO("fd=%d, epollfd=%d", iEventFd, m_iEpollFd);

    return HTTP_OK;
}